using System;
using System.Collections.Generic;

namespace UnityEngine.Recorder
{
	public abstract class Recorder : ScriptableObject
	{
		private static int sm_CaptureFrameRateCount;

		private bool m_ModifiedCaptureFR;

		protected List<RecorderInput> m_Inputs;

		public int recordedFramesCount
		{
			get;
			set;
		}

		public abstract RecorderSettings settings
		{
			get;
			set;
		}

		public bool recording
		{
			get;
			protected set;
		}

		public virtual void Awake()
		{
			sm_CaptureFrameRateCount = 0;
		}

		public virtual void Reset()
		{
			recordedFramesCount = 0;
			recording = false;
		}

		protected virtual void OnDestroy()
		{
			if (!m_ModifiedCaptureFR)
			{
				return;
			}
			sm_CaptureFrameRateCount--;
			if (sm_CaptureFrameRateCount == 0)
			{
				Time.captureFramerate = 0;
				if (Verbose.enabled)
				{
					UnityEngine.Debug.Log("Recorder resetting 'CaptureFrameRate' to zero");
				}
			}
		}

		public virtual void SessionCreated(RecordingSession session)
		{
			if (Verbose.enabled)
			{
				UnityEngine.Debug.Log($"Recorder {GetType().Name} session created");
			}
			settings.SelfAdjustSettings();
			int num = (settings.m_FrameRateMode == FrameRateMode.Constant) ? ((int)settings.m_FrameRate) : 0;
			if (num > 0)
			{
				if (Time.captureFramerate != 0 && num != Time.captureFramerate)
				{
					UnityEngine.Debug.LogError($"Recorder {GetType().Name} is set to record at a fixed rate and another component has already set a conflicting value for [Time.captureFramerate], new value being applied : {num}!");
				}
				else if (Time.captureFramerate == 0 && Verbose.enabled)
				{
					UnityEngine.Debug.Log("Frame recorder set fixed frame rate to " + num);
				}
				Time.captureFramerate = num;
				sm_CaptureFrameRateCount++;
				m_ModifiedCaptureFR = true;
			}
			m_Inputs = new List<RecorderInput>();
			foreach (RecorderInputSetting inputsSetting in settings.inputsSettings)
			{
				RecorderInput recorderInput = Activator.CreateInstance(inputsSetting.inputType) as RecorderInput;
				recorderInput.settings = inputsSetting;
				m_Inputs.Add(recorderInput);
				SignalInputsOfStage(ERecordingSessionStage.SessionCreated, session);
			}
		}

		public virtual bool BeginRecording(RecordingSession session)
		{
			if (recording)
			{
				throw new Exception("Already recording!");
			}
			if (Verbose.enabled)
			{
				UnityEngine.Debug.Log($"Recorder {GetType().Name} starting to record");
			}
			return recording = true;
		}

		public virtual void EndRecording(RecordingSession ctx)
		{
			if (!recording)
			{
				return;
			}
			recording = false;
			if (m_ModifiedCaptureFR)
			{
				m_ModifiedCaptureFR = false;
				sm_CaptureFrameRateCount--;
				if (sm_CaptureFrameRateCount == 0)
				{
					Time.captureFramerate = 0;
					if (Verbose.enabled)
					{
						UnityEngine.Debug.Log("Recorder resetting 'CaptureFrameRate' to zero");
					}
				}
			}
			foreach (RecorderInput input in m_Inputs)
			{
				((IDisposable)input)?.Dispose();
			}
			if (Verbose.enabled)
			{
				UnityEngine.Debug.Log($"{GetType().Name} recording stopped, total frame count: {recordedFramesCount}");
			}
		}

		public abstract void RecordFrame(RecordingSession ctx);

		public virtual void PrepareNewFrame(RecordingSession ctx)
		{
		}

		public virtual bool SkipFrame(RecordingSession ctx)
		{
			return !recording || ctx.frameIndex % settings.m_CaptureEveryNthFrame != 0 || (settings.m_DurationMode == DurationMode.TimeInterval && ctx.m_CurrentFrameStartTS < (double)settings.m_StartTime) || (settings.m_DurationMode == DurationMode.FrameInterval && ctx.frameIndex < settings.m_StartFrame) || (settings.m_DurationMode == DurationMode.SingleFrame && ctx.frameIndex < settings.m_StartFrame);
		}

		public void SignalInputsOfStage(ERecordingSessionStage stage, RecordingSession session)
		{
			if (m_Inputs != null)
			{
				switch (stage)
				{
				case ERecordingSessionStage.SessionCreated:
					foreach (RecorderInput input in m_Inputs)
					{
						input.SessionCreated(session);
					}
					break;
				case ERecordingSessionStage.BeginRecording:
					foreach (RecorderInput input2 in m_Inputs)
					{
						input2.BeginRecording(session);
					}
					break;
				case ERecordingSessionStage.NewFrameStarting:
					foreach (RecorderInput input3 in m_Inputs)
					{
						input3.NewFrameStarting(session);
					}
					break;
				case ERecordingSessionStage.NewFrameReady:
					foreach (RecorderInput input4 in m_Inputs)
					{
						input4.NewFrameReady(session);
					}
					break;
				case ERecordingSessionStage.FrameDone:
					foreach (RecorderInput input5 in m_Inputs)
					{
						input5.FrameDone(session);
					}
					break;
				case ERecordingSessionStage.EndRecording:
					foreach (RecorderInput input6 in m_Inputs)
					{
						input6.EndRecording(session);
					}
					break;
				default:
					throw new ArgumentOutOfRangeException("stage", stage, null);
				}
			}
		}
	}
}
